package me.cabbit.digitone.support;

public class Matrix {

	public static Matrix multiply (Matrix a, Matrix b) throws InvalidMatrixSizeException
	{
		//if the column number of the first matrix does not
		//match the rows number of the second matrix, throw
		//an exception
		if (a.cols != b.rows)
			throw new InvalidMatrixSizeException();
		
		//build the result matrix (rows of the first x cols of the second)
		Matrix result = new Matrix(a.rows, b.cols);

		//number of elements
		int elements = result.rows * result.cols;
		
		//indices for matrix a and b
		int ia, ib;
		
		//calculate every element on the result matrix
		for (int i = 0; i < elements; i++) 
		{
			//I came up with these in a moment of 
			//inspiration. Don't ask me how they work.
			//Figure it out D:)
			//they get the indices for each matrix, without the need
			//of a third loop
			ia = (i / result.cols) * a.cols;
			ib = (i % result.cols);
			
			//element_ij = a_row_i x b_col_j 
			for (int j = 0; j < a.cols; j++) 
			{
				result.values[i] += a.values[ia] * b.values[ib];
				
				ia ++;			//next element in the row				
				ib += b.cols;	//next element in the column
			}
		}
		
		return result;	
	}
	
	private double [] values;
	private int rows;
	private int cols;

	public Matrix(int rows, int cols)
	{
		this.rows = rows;
		this.cols = cols;
		
		this.values = new double[rows * cols];
	}
	
	public Matrix(int rows, int cols, double [] values)
	{
		this.rows = rows;
		this.cols = cols;

		set(values);
	}
	
	public void set(int x, int y, double val)
	{
		this.values[x + y * this.cols] = val;
	}

	public void set(double [] values) throws InvalidMatrixSizeException
	{
		if (values.length != this.rows * this.cols)
			throw new InvalidMatrixSizeException();
		this.values = values;
	}

	public double get (int x, int y)
	{
		return this.values[x + y * this.cols];
	}
	
	public Matrix multiply (Matrix m) throws InvalidMatrixSizeException
	{
		return Matrix.multiply(this, m);
	}
	
}
